package com.hd123.rumba.qt.html;

import java.io.IOException;
import java.io.PrintStream;
import java.math.BigDecimal;
import java.util.List;

import javax.servlet.jsp.JspWriter;

import com.hd123.rumba.qt.def.SQLColumn;
import com.hd123.rumba.qt.def.SQLColumnList;
import com.hd123.rumba.qt.report.PaperDefinition;
import com.hd123.rumba.request.JspLib;
import com.hd123.rumba.sql.JdbcRow;

/**
 * 构造数据集的htm table. <br>
 * 主方法: print(). <br>
 * 调用例子: TestPrintTable
 * 
 * @author caili, 2006-12-21
 */
public class PrintTable {

  /**
   * 输出目的
   */
  private MyWriter out;
  /**
   * 
   */
  private SQLColumnList visibleColumns;
  /**
   * 数据集
   */
  private List results;
  /**
   * 总合计数据集
   */
  private List summary;
  /**
   * 列名
   */
  private List names;
  /**
   * 下一查询集
   */
  private List nextQueryNames;
  /**
   * td的nowrap取值
   */
  private String nowrap = "nowrap";

  public void setOut(PrintStream out) throws IOException {
    this.out = new MyWriter(out);
  }

  public void setOut(JspWriter out) {
    this.out = new MyWriter(out);
  }

  public void setAggregator(BigDecimal[][] aggregator) {
    this.aggregator = aggregator;
  }

  public void setVisibleColumns(List visibleColumns) {
    this.visibleColumns = (SQLColumnList) visibleColumns;
    computeGroupInfo();
  }

  public void setNames(List names) {
    this.names = names;
  }

  public void setNextQueryNames(List nextQueryNames) {
    this.nextQueryNames = nextQueryNames;
  }

  public void setResults(List results) {
    this.results = results;
  }

  public void setSummary(List summary) {
    this.summary = summary;
  }

  public void setNowrap(String nowrap) {
    this.nowrap = nowrap;
  }

  public void print() throws Exception {
    print(null, null, null, null);
  }

  /**
   * 专给打印用. 显示则调用print()
   * 
   * @param width
   * @param title
   * @param info
   * @param visibleFields
   *          要打印的列. 是visibleColumns的子集. 每个元素对应一个列.
   * @throws Exception
   */
  public void print(Integer width, String title, String info, boolean[] visibleFields)
      throws Exception {
    String swidth = "100%";
    if (width != null)
      swidth = (width.intValue() - PaperDefinition.DefaultLeftMargin - PaperDefinition.DefaultRightMargin)
          * 96 / 25.4 + "px";
    out.println("<table id=dataTable cellspacing=0 cellpadding=4 width=" + swidth + "><tbody>");

    if (title != null) {
      int colspan = 0;
      for (int i = 0; i < visibleFields.length; ++i) {
        if (visibleFields[i])
          colspan++;
      }
      out.println("<tr><td colspan='" + colspan + "' align=center style='font-size:14pt'>" + title
          + "</td></tr>");
      if (info != null)
        out.println("<tr><td colspan='" + colspan + "'>" + info + "</td></tr>");
    }
    this.visibleFields = visibleFields;
    if (getGroupedColumnCount() > 0)
      printGroupedTable();
    else
      printPlainTable();

    out.println("</tbody></table>");
  }

  /**
   * 要打印的列. 是visibleColumns的子集. 每个元素对应一列.
   * visibleFields.length==visibleColumns.size()
   */
  private boolean[] visibleFields = null;
  private String cw = "border-left:.5pt solid #555555;";
  private String cn = "border-top:.5pt solid #555555;";
  private String ce = "border-right:.5pt solid #555555;";
  private String cs = "border-bottom:.5pt solid #555555;";
  private String cb = "font-weight:bold;";

  public void printPlainTable() throws Exception {
    out.println("<tr class='table_header'>");
    String w = cw;
    for (int i = 0; i < visibleColumns.size(); ++i) {
      if (visibleFields == null || visibleFields[i]) {
        out.print("<td " + nowrap + " align=center style='" + cb + w + cn + ce + cs + "'>");
        out.print(((SQLColumn) visibleColumns.get(i)).getTitle());
        out.println("</td>");
        w = "";
      }
    }
    out.println("</tr>");

    for (int j = 0; j < results.size(); ++j) {
      JdbcRow row = (JdbcRow) results.get(j);
      out.println("<tr class='" + (j % 2 == 0 ? "table_detail" : "table_detail_odd") + "'>");
      w = cw;
      boolean printNextLink = nextQueryNames != null && nextQueryNames.size() > 0;

      // if (visibleFields == null || visibleFields[0]) {
      // out.print("<td " + nowrap + " style='" + w + ce + cs + "'>");
      // if (nextQueryNames != null && nextQueryNames.size() > 0)
      // out.print("<a href='#' onClick=\"runNextQuery('" + row.get("uuid")
      // + "')\">");
      // out.print(getValue(row.get(names.get(0)), null));
      // if (nextQueryNames != null && nextQueryNames.size() > 0)
      // out.print("</a>");
      // out.print("</td>");
      // w = "";
      // }

      for (int k = 0; k < visibleColumns.size(); k++) {
        if (visibleFields == null || visibleFields[k]) {
          Object value = row.get(names.get(k));
          String pattern = ((SQLColumn) visibleColumns.get(k)).getPattern();
          out.print("<td " + nowrap + " " + getAlign(value) + " " + getExcelTag(value) + " style='"
              + w + ce + cs + "'>");
          if (printNextLink)
            out.print("<a href='#' onClick=\"runNextQuery('" + row.get("uuid") + "')\">");
          out.print(getValue(value, pattern));
          if (printNextLink) {
            out.print("</a>");
            printNextLink = false;
          }
          out.print("</td>");
          w = "";
        }
      }
      out.println("</tr>");
    }

    if (summary != null && summary.size() > 0) {
      for (int j = 0; j < summary.size(); j++) {
        if (visibleFields == null || visibleFields[j]) {
          JdbcRow row = (JdbcRow) summary.get(j);
          out.println("<tr style=\"background-color:#FFFF88\">");
          out.print("<td " + nowrap + " style='" + cw + ce + cs + "'><b>"
              + getValue(row.get(names.get(0)), ((SQLColumn) visibleColumns.get(0)).getPattern())
              + "</b></td>");
          for (int k = 1; k < visibleColumns.size(); k++) {
            if (visibleFields == null || visibleFields[k]) {
              Object value = row.get(names.get(k));
              out.print("<td " + nowrap + " style='" + ce + cs + cb + "' " + getAlign(value) + " "
                  + getExcelTag(value) + ">");
              out.print(getValue(value, ((SQLColumn) visibleColumns.get(k)).getPattern()));
              out.print("</td>");
            }
          }
          out.println("</tr>");
        }
      }
    }
  }

  public void printGroupedTable() throws Exception {
    out.println("<tr class='table_header'>");
    printLeadCells(cn);
    String w = "";
    for (int i = 0; i < visibleColumns.size(); ++i) {
      if (visibleFields == null || visibleFields[i]) {
        if (visibleColumns.get(i).getGroupIndex() == -1) {
          out.print("<td " + nowrap + " align=center style='" + cb + w + cn + ce + cs + "'>");
          out.print(((SQLColumn) visibleColumns.get(i)).getTitle());
          out.println("</td>");
          w = "";
        }
      }
    }
    int lastRowLevel = -1;
    int rowLevel = -1;
    JdbcRow lastRow = null;
    for (int irow = 0; irow < results.size(); ++irow) {
      JdbcRow row = (JdbcRow) results.get(irow);
      rowLevel = getRowLevel(row, lastRow);
      // System.out.println(getMaxLevel() + " " + irow + " " + lastRowLevel + "
      // " + rowLevel);
      if (rowLevel != getMaxLevel()) {
        if (lastRowLevel != -1) {
          for (int i = getMaxLevel() - 1; i >= rowLevel; --i) {
            printSummaryRow(i);
            resetAggregator(i);
          }
        }
        for (int i = rowLevel; i < getMaxLevel(); ++i) {
          printHeadRow(row, i);
        }
      }
      printDataRow(row);
      aggregate(row);
      lastRowLevel = rowLevel;
      lastRow = row;
    }
    for (int i = rowLevel - 1; i >= 0; --i)
      printSummaryRow(i);
    printSummaryRow(getMaxLevel());
  }

  private void printLeadCells(String n) throws IOException {
    String w = cw;
    for (int i = 0; i < getGroupedColumnCount(); ++i) {
      out.println("<td width=8 style='" + w + n + ce + cs + "'>&nbsp;</td>");
      w = "";
    }
  }

  private void printHeadRow(JdbcRow row, int rowLevel) throws Exception {
    out.print("<tr bgcolor='#eeeeee'>");
    // out.print("<td>h" + rowLevel + "</td>");
    String w = cw;
    for (int j = 0; j < rowLevel; ++j) {
      out.print("<td width=8 style='" + w + ce + cs + "'>&nbsp;</td>");
      w = "";
    }
    String name = "A";
    // int titleIndex = 0;
    for (int i = 0; i < visibleColumns.size(); ++i) {
      if (visibleColumns.get(i).getGroupIndex() == rowLevel) {
        name = (String) names.get(i);
        // titleIndex = i;
        break;
      }
    }
    out.print("<td style='" + w + ce + cs + "' colspan=" + (names.size() - rowLevel) + ">");
    String value = getValue(row.get(name), null);
    if ("&nbsp;".equals(value))
      value = "(空)";
    // out.print(((SQLColumn) visibleColumns.get(titleIndex)).getTitle() + ":
    // ");
    out.print(value);
    out.print("</td>");
    out.println("</tr>");
  }

  private void printDataRow(JdbcRow row) throws Exception {
    boolean printNextLink = nextQueryNames != null && nextQueryNames.size() > 0;
    out.print("<tr bgcolor=white ");
    // if (printNextLink) {
    // out.print(" onClick=\"runNextQuery('" + row.get("uuid") + "')\"");
    // }
    out.print(">");
    printLeadCells("");
    // out.print("<td>d" + rowLevel + "</td>");
    for (int i = 0; i < names.size(); ++i) {
      if (visibleColumns.get(i).getGroupIndex() == -1) {
        if (visibleFields == null || visibleFields[i]) {
          Object value = row.get(names.get(i));
          out.print("<td style='" + ce + cs + "' nowrap " + getAlign(value) + " "
              + getExcelTag(value) + ">");
          if (printNextLink)
            out.print("<a href='#' onClick=\"runNextQuery('" + row.get("uuid") + "')\">");
          out.print(getValue(value, ((SQLColumn) visibleColumns.get(i)).getPattern()));
          if (printNextLink) {
            out.print("</a>");
            printNextLink = false;
          }
          out.print("</td>");
        }
      }
    }
    out.println("</tr>");
  }

  private void printSummaryRow(int rowLevel) throws IOException {
    if (!hasSummary)
      return;
    String bgcolor = "#eeeeee";
    String style = "";
    if (rowLevel == getMaxLevel()) {
      bgcolor = "ffff88";
      style = "style='font-weight:bold'";
    }
    out.print("<tr bgcolor='" + bgcolor + "'>");
    // out.print("<td>s" + rowLevel + "</td>");
    String w = cw;
    for (int k = 0; k < visibleColumns.size(); ++k) {
      // 这里的k是打印出来的列的下标. 考虑到被分组的列不一定是visibleColumns的头上几列, 需要计算第k打印列对应的查询列i:
      // 计算第k列后有几个分组列n, 相应的visibleColumns则是k-n. 如果k-n<0, 则打印空白(leadingCells).
      int n = 0;
      for (int in = k; in < visibleColumns.size(); ++in)
        if (visibleColumns.get(in).getGroupIndex() != -1)
          ++n;
      int i = k - n;
      if (i < 0) {
        out.print("<td style='" + w + ce + cs + "' align=right " + style + ">&nbsp;</td>");
        w = "";
      } else {
        if (visibleFields == null || visibleFields[i]) {
          out.print("<td style='" + w + ce + cs + "' align=right " + style + ">");
          if (visibleColumns.get(i).getGAggregation() != null
              && !"".equals(visibleColumns.get(i).getGAggregation())) {
            out.print(getValue(aggregator[rowLevel][i], ((SQLColumn) visibleColumns.get(i))
                .getPattern()));
          } else {
            out.print("&nbsp;");
          }
          out.print("</td>");
          w = "";
        }
      }
    }
    out.println("</tr>");
  }

  private int getRowLevel(JdbcRow row, JdbcRow lastRow) {
    if (lastRow == null)
      return 0;
    int level = getMaxLevel();
    for (int i = 0; i < visibleColumns.size(); ++i) {
      if (visibleColumns.get(i).getGroupIndex() != -1) {
        if (row.get(names.get(i)) != null
            && !row.get(names.get(i)).equals(lastRow.get(names.get(i)))
            || row.get(names.get(i)) == null && lastRow.get(names.get(i)) != null) {
          if (level > visibleColumns.get(i).getGroupIndex())
            level = visibleColumns.get(i).getGroupIndex();
        }
      }
    }
    return level;
  }

  private int groupedColumnCount = -1;
  private int maxLevel = -1;
  private boolean hasSummary = false;
  // aggregator[0]放的是第0层的合计, [1]是第1层的合计, ..., [getMaxLevel()]放的是总合计.
  private BigDecimal[][] aggregator = null;

  private void computeGroupInfo() {
    int level = -1;
    int count = 0;
    for (int i = 0; i < visibleColumns.size(); ++i) {
      if (visibleColumns.get(i).getGroupIndex() > level) {
        level = visibleColumns.get(i).getGroupIndex();
      }
      if (visibleColumns.get(i).getGroupIndex() != -1) {
        ++count;
      }
      if (visibleColumns.get(i).getGAggregation() != null
          && !visibleColumns.get(i).getGAggregation().equals("")) {
        hasSummary = true;
      }
    }
    maxLevel = level + 1;
    groupedColumnCount = count;

    aggregator = new BigDecimal[maxLevel + 1][visibleColumns.size()];
    for (int i = 0; i <= maxLevel; ++i) {
      for (int j = 0; j < visibleColumns.size(); ++j) {
        aggregator[i][j] = BigDecimal.ZERO;
      }
    }
  }

  private int getMaxLevel() {
    return maxLevel;

  }

  private int getGroupedColumnCount() {
    return groupedColumnCount;
  }

  private void resetAggregator(int level) {
    for (int i = level; i < getMaxLevel(); ++i) {
      for (int j = 0; j < visibleColumns.size(); ++j) {
        aggregator[i][j] = BigDecimal.ZERO;
      }
    }
  }

  private void aggregate(JdbcRow row) {
    for (int i = 0; i < aggregator.length; ++i) {
      for (int j = 0; j < visibleColumns.size(); ++j) {
        if ("SUM".equalsIgnoreCase(visibleColumns.get(j).getGAggregation())) {
          BigDecimal num = BigDecimal.ZERO;
          if (row.get(names.get(j)) != null)
            num = new BigDecimal(row.get(names.get(j)).toString());
          aggregator[i][j] = aggregator[i][j].add(num);
        } else if ("COUNT".equalsIgnoreCase(visibleColumns.get(j).getGAggregation())) {
          aggregator[i][j] = aggregator[i][j].add(BigDecimal.ONE);
        }
      }
    }
  }

  private String getAlign(Object value) {
    if (value instanceof Number)
      return "align=right";
    else if (value instanceof java.util.Date)
      return "align=center";
    return "";
  }

  private String getExcelTag(Object value) {
    if (value instanceof Number)
      return ("x:num");
    return "";
  }

  private String getValue(Object value, String pattern) {
    if (value != null) {
      String s = "";
      // 如果内容是<img开始的, 不要format. 2007-3-1
      if (value instanceof String && ((String) value).toLowerCase().startsWith("<img"))
        s = (String) value;
      else if (value instanceof String && ((String) value).toLowerCase().startsWith("<a href"))
        s = (String) value;
      else
        s = JspLib.format(value, pattern);
      if ("".equals(s))
        return "&nbsp;";
      else
        return s;
    } else
      return "&nbsp;";
  }
}
